﻿using System;
using System.IO;
using System.Threading;
using LumiSoft.Net.Media.Codec.Audio;
using LumiSoft.Net.RTP;
using TEL.WinMediaWPF.Audio.Wav;

namespace TEL.WinMediaWPF.Audio
{
    /// <summary>
    /// This class implements RTP audio sender.
    /// </summary>
    public class RTP_AudioSender
    {
        private bool           m_IsDisposed = false;
        private Stream         m_pSource    = null;
        private RTP_SendStream m_pRtpStream = null;
        private RTP_Packet     m_pRtpPacket = null;
        private WAVFile        m_pWavFile   = null;
        private int m_pDefaultPayload =0;
        public string AnswerFileName { get; set; }
        public bool IsAnswer { get; set; }
        public string LineCall { get; set; }
        public bool IsActive { get; set; }

        public class StringEventArgs : EventArgs
        {
            public string Message { get; private set; }
            public StringEventArgs(string msg)
            {
                Message = msg;
            }
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stream">RTP stream.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception>
        public RTP_AudioSender(RTP_SendStream stream)
        {
            if(stream == null){
                throw new ArgumentNullException("stream");
            }

            m_pRtpStream = stream;
            m_pDefaultPayload = m_pRtpStream.Session.Payload;
            m_pRtpPacket = new RTP_Packet();

            Thread tr = new Thread(this.SendAudio);
            tr.Start();
        }

        #region method Dispose

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if(m_IsDisposed){
                return;
            }
            m_IsDisposed = true;
        }

        #endregion
        /// <summary>
        /// Начинаем запись в <b>WAV</b> фаил
        /// </summary>
        /// <param name="fileName">Имя нового фаила </param>
        public void StartSaving(string fileName)
        {
            if (File.Exists(fileName)) File.Delete(fileName);

            m_pWavFile = new WAVFile();
            m_pWavFile.Create(fileName, false, 8000, 16);
        }

        public Stream LoadAnswer(string fileName)
        {
            AnswerFileName = fileName;
            return new FileStream(fileName, FileMode.Open);
        }

        /// <summary>
        /// Остановка записи <b>WAV</b> фаил
        /// Закрытия фаила
        /// </summary>
        public void StopSaving()
        {
            if (m_pWavFile != null)
            {
                m_pWavFile.Close();
                m_pWavFile = null;
            }
        }

        void ReseiverToWav(byte[] content)
        {
            if (m_pWavFile == null) return;
            MemoryStream stream = new MemoryStream(content);
            int bits = m_pWavFile.BitsPerSample/8;
            int r = bits;
            byte[] bytes = new byte[bits];
            while (r > 0)
            {
                r = stream.Read(bytes, 0, bits);

                m_pWavFile.AddSample_ByteArray(bytes);
            }
        }

        #region method SendAudio

        public event EventHandler<StringEventArgs> AnswerEnd;
      //  public event EventHandler<AudioSenderEventArgs> AudioSenderEvent = null;
        /// <summary>
        /// Sends audio in audio to RTP stream.
        /// </summary>
        private void SendAudio()
        {            
            int    ptime      = 20;
            byte[] readBuffer = new byte[320];
            while(!m_IsDisposed)
            {
                try{
                    if(IsActive && m_pSource != null  &&  m_pRtpStream.Session.Payload == m_pDefaultPayload)
                    {
                        int readedCount = m_pSource.Read(readBuffer,0,readBuffer.Length);
                        if(readedCount == 0){
                            Thread.Sleep(1);
                            if (IsAnswer && AnswerEnd != null && !string.IsNullOrEmpty(AnswerFileName))
                                AnswerEnd(this, new StringEventArgs(AnswerFileName));
                             continue;
                        }
                        if (m_pWavFile != null) ReseiverToWav(readBuffer);
                       
                        m_pRtpPacket.Data = m_pRtpStream.Session.Payloads[m_pRtpStream.Session.Payload].Encode(readBuffer,0,readedCount);
                        m_pRtpPacket.Timestamp = m_pRtpStream.Session.RtpClock.RtpTimestamp;
                        m_pRtpStream.Send(m_pRtpPacket);

                        Thread.Sleep(ptime);
                        
                    }
                }
                catch(ObjectDisposedException x){
                    string dummy = x.Message;

                    // RTP session disposed, dispose sender.
                    Dispose();

                    return;
                }
                catch{
                }
            }          
        }

        public void ToneSend(Byte but, Stream stream)
        {
            m_pRtpStream.Session.Payload = 101;
            stream.Position = 0;
            int readMax = 0;
            int readCount = 1;
            byte[] buf = new byte[164];
            buf[0] = but;
            buf[1] = 10;
            while (readCount > 0)
            {
                readCount = stream.Read(buf, 4, 160);
                readMax += readCount;
                int ost = 0;
                int i = Math.DivRem(readMax, 256, out ost);
                buf[2] = (byte) i;
                buf[3] = (byte) ost;

                m_pRtpPacket.Data = buf;
                
                m_pRtpPacket.Timestamp = m_pRtpStream.Session.RtpClock.RtpTimestamp;
                m_pRtpStream.Send(m_pRtpPacket);
            }
            buf[1] = 138;
            m_pRtpPacket.Data = buf;
            m_pRtpPacket.Timestamp = m_pRtpStream.Session.RtpClock.RtpTimestamp;
            m_pRtpStream.Send(m_pRtpPacket);

            m_pRtpStream.Session.Payload = m_pDefaultPayload;
        }

        #endregion


        #region Properties implementation

        /// <summary>
        /// Gets source stream. Audio must be 16khz,16-bit,1-channel.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public Stream 
            Source
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }
                
                return m_pSource; 
            }

            set{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                m_pSource = value;
            }
        }

        #endregion
    }
}
